package com.cskaoyan.javase.oop3._2inner._1member._1basic;

/**
 * 成员内部类的访问特点(重点)
 * 定义成员内部类是基于两大最主要的需求的:
 *      1.为了隐藏内部类,私有的成员内部类在外部是访问不到
 *      2.为了让成员内部类和外围类,这两个类之间的访问,不受权限限制,随意访问.
 *
 * 要想搞清楚成员内部类和外围类之间互相访问的特点,我们要明确以下两点:
 *      1.成员内部类和外围类是"自己人",是"好兄弟",它们之间的互相访问全部都不受权限限制.
 *      2.成员内部类相当于外围类的一个成员
 *          --> 要想创建成员内部类对象,需要在外围类对象的基础上创建
 *          --> 成员内部类对象,会持有外围类对象的引用作为自身成员变量
 *      以上结论,具体表示什么意义呢?思考以下几个问题:
 *          a.在成员内部类的成员方法中,存在几个对象?
 *              首先必然存在this,必然存在自身成员内部类对象
 *              其次还存在外围类对象(因为成员内部类对象必须在外围类对象的基础上创建,既然成员内部类对象存在,那么外围类对象肯定也存在)
 *              这两个对象在成员内部类当中的成员方法中,用不同的关键字和词组指向:
 *              this指向自身成员内部类对象
 *              "外围类类名.this"指向外围类对象
 *
 *         b.在成员内部类的静态成员方法中,存在几个对象呢?
 *         成员内部类没有静态声明,所以这题目错了
 *
 *         c.外围类的成员方法中,有几个对象?
 *              一个,this指向自身外围类对象
 *              成员内部类依赖于外围类
 *              外围类不依赖于成员内部类
 *
 *         d.外围类的静态成员方法中,有几个对象?
 *              啥也没有,一个对象都没有
 *              想要用对象,都必须自己创建
 *
 * 成员内部类的访问特点，主要从以下几个角度研究：
 *      1.成员内部类内部访问外围类(重点)
 *          要想访问外围类成员,访问的位置必然是成员内部类当中的成员方法
 *          这时有两个对象了,并且已经存在外围类对象了
 *          这时想要访问外围类,直接访问就可以了
 *          并且不受权限限制
 *
 *          当然,如果出现成员内部类和外围类成员同名的情况:
 *          用this指向当前成员内部类对象
 *          外围类类名.this指向外围类对象
 *          来区分
 *
 *      2.外围类访问成员内部类成员(重点)
 *        以下两种位置的访问,相同点是都没有成员内部类对象,都需要创建成员内部类对象.但是创建的方式是不同的
 *       创建成员内部类对象, 需要在外围类对象的基础上创建
 *        a.外围类的成员方法中访问成员内部类成员
 *              存在this,存在自身外围类对象
 *              所以创建成员内部类对象: 可以直接创建
 *              创建出来以后,用对象访问它的成员即可,不受权限限制.
 *
 *        b.外围类的静态成员方法中访问成员内部类成员
 *              没有任何对象
 *              所以要想得到成员内部类对象
 *              需要先创建外围类对象
 *              再创建成员内部类对象
 *          创建对象之后,任意访问即可,不受权限限制
 *
 *      3.外部类访问成员内部类成员(了解即可)
 *          外部类和成员内部类没有任何关系
 *          要想访问成员内部类成员,全程都受权限限制
 *          首先要有外围类权限,其次还需要成员内部类的权限,最后还需要该成员的权限
 *
 *          如果全程都有权限的话,那么它的访问语法是: 先创建外围类对象,再创建成员内部类对象
 *          创建成员内部类对象,在外部类中,无论是成员方法,还是静态方法,都是没有任何区别的
 *          因为反正都没有外围类对象,都需要先创建外围类对象,再创建成员内部类对象
 *          语法:
 *           EnclosedClazz ec = new EnclosedClazz();
 *           // 在外部使用成员内部类引用时,需要指明该内部类属于哪个外围类
 *           EnclosedClazz.InnerClazz ic = ec.new InnerClazz();
 *
 *      4.成员内部类访问外部类成员(了解即可)
 *          可以访问,但是要创建对象
 *          全程都受权限限制
 *          这无非就是两个类之间的访问,没有区别
 *
 * 什么时候使用成员内部类?
 *      1.隐藏类
 *      2.为了和外围类之间能够互相访问,不受权限限制
 *      3.(独特)如果希望定义的内部类可以直接访问外围类成员
 *          那就需要定义成员内部类
 *
 * @since 11:23
 * @author wuguidong@cskaoyan.onaliyun.com
 */
public class Demo {
    public static void main(String[] args) {
        EnclosedClazz ec = new EnclosedClazz();
        // 在外部使用成员内部类引用时,需要指明该内部类属于哪个外围类
        EnclosedClazz.InnerClazz ic = ec.new InnerClazz();

        EnclosedClazz.InnerClazz ic2 = new EnclosedClazz().new InnerClazz();

        System.out.println(ic.a);
        // 'b' has private access in 'com.cskaoyan.javase.oop3._2inner._1member._1basic.EnclosedClazz.InnerClazz'
        // System.out.println(ic.b);
    }
}

// 外围类
class EnclosedClazz {
    int a = 10;
    private int b = 20;
    private static int c = 30;
    static final int D = 40;

    // 外围类的成员方法
    public void testEnclosed(){
        // 直接new创建成员内部类对象
        InnerClazz ic = new InnerClazz();
        System.out.println(ic.a);
        System.out.println(ic.b);

        // 什么叫在外围类对象的基础上,创建成员内部类对象,这里的"this."可以省略
        InnerClazz ic2 = this.new InnerClazz();
    }
    // 外围类的静态成员方法
    public static void testStaticEnclosed(){
        // 先创建外围类对象
        EnclosedClazz ec = new EnclosedClazz();
        // 在外围类对象的基础上,创建成员内部类对象
        InnerClazz ic = ec.new InnerClazz();
        // 当然上述,可以链式调用,二合一
        InnerClazz ic2 = new EnclosedClazz().new InnerClazz();
        System.out.println(ec.a);
        System.out.println(ic.a);
    }


    // 成员内部类
    class InnerClazz {
        int a = 100;
        private int b = 200;
        // private static int c = 300;
        static final int D = 400;

        public void accessA(int a){
            System.out.println(a);
            System.out.println(this.a);
            System.out.println(EnclosedClazz.this.a);
        }

        // 成员内部类当中的成员方法
        public void testInner() {
            /*
                这里存在两个对象
                this指向当前成员内部类对象
                外围类类名.this指向外围类对象
              */
            System.out.println(a);
            System.out.println(b);
            System.out.println(EnclosedClazz.this.a);
            System.out.println(EnclosedClazz.this.b);
            System.out.println(EnclosedClazz.c);
            System.out.println(EnclosedClazz.D);
        }
    }
}